package com.piece.core.db.config;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
import com.alibaba.druid.util.Utils;
import com.piece.core.db.context.DynamicDataSource;
import com.piece.core.db.initializer.DataSourceInitializer;
import com.piece.core.db.initializer.DataSourceScript;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.enums.WebFilterOrder;
import com.piece.core.framework.util.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import javax.annotation.Resource;
import javax.servlet.*;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Druid 多数据源配置类
 *
 * <p>
 * 需要配置如下参数：<br>
 * spring.datasource.druid.master 主数据库相关项(必配)<br>
 * spring.datasource.druid.slave  从数据库相关项<br>
 * </p>
 */
@Slf4j
public class DruidAutoConfig {

    @Resource
    private List<DataSourceScript> dataSourceScript;

    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    public DataSource dataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Primary
    @Bean("dynamicDataSource")
    public DynamicDataSource dataSource(DataSource dataSource, Environment environment) {
        Binder binder = Binder.get(environment);
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(FrameWorkConstants.DATASOURCE_MASTER, dataSource);
        Boolean enableSlave = binder.bind("spring.datasource.druid.enable-slave", Boolean.class).get();
        if (null != enableSlave && enableSlave) {
            // 获取其他数据源配置
            List<Map> configs = binder.bind("spring.datasource.druid.slave", Bindable.listOf(Map.class)).get();
            String key;
            Map config;
            DataSource customerDatasource;
            // 遍历从数据源
            for (int i = 0; i < configs.size(); i++) {
                config = configs.get(i);
                key = null != config.get("key") ? config.get("key").toString() : null;
                if (StringUtil.isNotEmpty(key)) {
                    // 绑定参数
                    try {
                        customerDatasource = DruidDataSourceFactory.createDataSource(config);
                        // 获取数据源的key，以便通过该key可以定位到数据源
                        targetDataSources.put(key, customerDatasource);
                    } catch (Exception e) {
                        log.error("获取数据源[{}]异常：{}", key, e.getMessage());
                    }
                }
            }
        }

        DynamicDataSource dynamicDataSource = new DynamicDataSource(dataSource, targetDataSources);
        // 创建数据表
        DataSourceInitializer initializer = new DataSourceInitializer(dynamicDataSource, dataSourceScript);
        initializer.runScript();

        return dynamicDataSource;
    }

    /**
     * 配置jdbcTemplate
     */
    @Bean("jdbcTemplate")
    public JdbcTemplate masterJdbcOperations(DynamicDataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean("namedParameterJdbcTemplate")
    public NamedParameterJdbcTemplate masterNamedParameterJdbcOperations(JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }

    /**
     * 去除监控页面底部的广告
     */
    @Bean
    @ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true")
    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties) {
        // 获取web监控页面的参数
        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
        // 提取common.js的配置路径
        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
        final String filePath = "support/http/resources/js/common.js";
        // 创建filter进行过滤
        Filter filter = new Filter() {
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
            }

            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                chain.doFilter(request, response);
                // 重置缓冲区，响应头不会被重置
                response.resetBuffer();
                // 获取common.js
                String text = Utils.readFromResource(filePath);
                // 正则替换banner, 除去底部的广告信息
                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
                text = text.replaceAll("powered.*?shrek.wang</a>", "");
                response.getWriter().write(text);
            }

            @Override
            public void destroy() {
            }
        };
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(filter);
        registrationBean.addUrlPatterns(commonJsPattern);
        registrationBean.setOrder(WebFilterOrder.DRUID_FILTER);
        return registrationBean;
    }
}
